import { ModifierKey } from '@antv/x6-common'
import { Edge, Graph } from '@antv/x6'
import { Snapline } from '@antv/x6-plugin-snapline'
import { Selection } from '@antv/x6-plugin-selection'
import { Transform } from '@antv/x6-plugin-transform'
import { History } from '@antv/x6-plugin-history'
import { Clipboard } from '@antv/x6-plugin-clipboard'
import { Keyboard } from '@antv/x6-plugin-keyboard'
import { Scroller } from '@antv/x6-plugin-scroller'
import { MiniMap } from '@antv/x6-plugin-minimap'
import GraphStore from '@/store/graphStore'
import { MessageInstance } from 'antd/es/message/interface'
import MetaStore from '@/store/metaStore'

export const MethodPortPosition: {
  LT: number
  RB: number
} = {
  LT: 60, // left top
  RB: 60, // right bottom
}

export const graphPlugInInit = (
  graph: Graph,
  graphStore: GraphStore,
  messageApi: MessageInstance,
  miniMapContainer: HTMLElement
) => {
  // 对齐线
  graph.use(new Snapline(snaplineOptions))
  // 框选，框选监听在MainGraph.tsx中
  graph.use(new Selection(selectionOptions(graphStore.graph)))
  // 图形变换
  graph.use(
    new Transform({
      resizing: transformOptions,
    })
  )
  // 撤销重做
  graph.use(new History(historyOptions))
  // 复制粘贴
  // TODO：useLocalStorage问题排查
  graph.use(new Clipboard(clipBoardOptions))
  // 快捷键
  graph.use(new Keyboard(keyboardOptions))
  customKeyBind(graph, graphStore, messageApi)
  // 滚动画布
  graph.use(
    new Scroller({
      enabled: true,
      pannable: true,
      pageVisible: false,
      autoResize: true,
      // modifiers: ['ctrl'] as ModifierKey[],
      padding: 120, // 设置画布四周的 padding 边距，在宽度和高度方向至少有 padding 大小的画布可见（可以理解为容器大小+padding为画布大小）
    })
  )
  graph.use(
    new MiniMap({
      container: miniMapContainer,
      width: 192,
      height: 150,
      padding: 10,
    })
  )
}

export const edgeInteractionHandler = (
  isNew: boolean,
  edge: Edge,
  messageApi: MessageInstance,
  metaStore: MetaStore
) => {
  // const metaStore = useMetaStore()
  if (isNew) {
    metaStore.onAddEdge(
      edge['store']['data']['source']['cell'],
      edge['store']['data']['target']['cell']
    )
    // 如果连线成功（新的边被创建）
    messageApi.success(
      `${edge['store']['data']['source']['cell']}---${edge['store']['data']['target']['cell']}`
    )
    // messageApi.success(
    //   `${edge['store']['data']['source']['port']}---${edge['store']['data']['target']['port']}`
    // )
  }
}

/* interface Options {
  enabled?: boolean
  modifiers?: ModifierKey
  eventTypes?: ('leftMouseDown' | 'rightMouseDown' | 'mouseWheel')[]
} */

// https://x6.antv.antgroup.com/api/graph/panning

export const panningOptions = {
  enabled: true,
  modifiers: ['ctrl', 'alt'] as ModifierKey[],
  eventTypes: ['leftMouseDown'] as (
    | 'leftMouseDown'
    | 'rightMouseDown'
    | 'mouseWheel'
  )[],
}

// -------------------------------------------------------------------------- //

/* interface Options {
  enabled?: boolean
  global?: boolean
  factor?: number
  zoomAtMousePosition?: boolean
  modifiers?: string | ('alt' | 'ctrl' | 'meta' | 'shift')[] | null
  guard?: (this: Graph, e: WheelEvent) => boolean
} */
// https://x6.antv.antgroup.com/api/graph/mousewheel

export const mousewheelOptions = {
  enabled: true,
  global: false,
  factor: 1.05, // 缩放因子
  zoomAtMousePosition: true,
  modifiers: ['ctrl', 'alt'] as ModifierKey[],
}

// -------------------------------------------------------------------------- //

// https://x6.antv.antgroup.com/tutorial/plugins/snapline

export const snaplineOptions = {
  // className: styles['test'],
  enabled: true,
  tolerance: 10,
  sharp: false,
  resizing: true,
  clean: false,
}

// -------------------------------------------------------------------------- //

// https://x6.antv.antgroup.com/tutorial/plugins/selection

export const selectionOptions = (targetGraph: Graph) => {
  targetGraph.setSelectionFilter((cell) => cell.id !== 'zmx123')

  return {
    enabled: true,
    multiple: true,
    modifiers: ['ctrl'] as ModifierKey[], // 按住ctrl才可框选
    multipleSelectionModifiers: ['ctrl'] as ModifierKey[], // 按住ctrl点击才可多选
    strict: false,
    rubberband: true,
    movable: true,
    showNodeSelectionBox: true,
    showEdgeSelectionBox: true,
    // 如果打开 showNodeSelectionBox 时，会在节点上方盖一层元素，导致节点的事件无法响应，此时可以配置 pointerEvents: none 来解决
    pointerEvents: 'none' as 'none' | 'auto',
  }
}

// -------------------------------------------------------------------------- //

// https://x6.antv.antgroup.com/tutorial/plugins/transform

export const transformOptions = {
  enabled: false, // 暂时禁用
  minWidth: 1,
  maxWidth: 200,
  minHeight: 1,
  maxHeight: 150,
  orthogonal: true,
  restrict: false,
  preserveAspectRatio: false,
}

// -------------------------------------------------------------------------- //

// https://x6.antv.antgroup.com/tutorial/plugins/history#%E9%85%8D%E7%BD%AE

export const historyOptions = {
  enabled: true,
}

// -------------------------------------------------------------------------- //

// https://x6.antv.antgroup.com/tutorial/plugins/clipboard

export const clipBoardOptions = {
  enabled: true,
  useLocalStorage: false,
}

// -------------------------------------------------------------------------- //

// https://x6.antv.antgroup.com/tutorial/plugins/keyboard

export const keyboardOptions = {
  enabled: true,
}
export const customKeyBind = (
  targetGraph: Graph,
  graphStore: GraphStore,
  messageApi: MessageInstance
) => {
  targetGraph.bindKey('ctrl+z', () => {
    targetGraph.undo() // 撤销
    messageApi.info({ content: '撤销' })
  })
  targetGraph.bindKey('ctrl+y', () => {
    targetGraph.redo() // 重做
    messageApi.info({ content: '重做' })
  })
  targetGraph.bindKey('delete', () => {
    graphStore.selectedCell.forEach((cell) => cell.remove()) // 删除
    messageApi.info({ content: '删除' })
  })
  targetGraph.bindKey('ctrl+c', () => {
    const cells = targetGraph.getSelectedCells()
    if (cells.length) {
      targetGraph.copy(cells) // 复制
      messageApi.info({ content: '已复制至剪贴板' })
    }
    return false
  })
  targetGraph.bindKey('ctrl+v', () => {
    if (!targetGraph.isClipboardEmpty()) {
      const cells = targetGraph.paste({ offset: 32 })
      targetGraph.cleanSelection()
      targetGraph.select(cells) // 粘贴
      messageApi.info({ content: '粘贴' })
    }
    return false
  })
}

// -------------------------------------------------------------------------- //

// https://x6.antv.antgroup.com/tutorial/basic/interacting

export const connectingOptions = {
  allowBlank: false, // 不允许连接到画布空白位置的点
  allowNode: false, // 不允许边连接到节点（非节点上的连接桩）
  highlight: true,
  connector: {
    name: 'smooth', // 全局连接边贝塞尔曲线
    args: {
      direction: 'H',
    },
  },
  validateConnection({ sourceCell, targetCell, sourceMagnet, targetMagnet }) {
    // 不能连接自身
    if (sourceCell === targetCell) {
      return false
    }

    // 只能从 out 连接桩开始连接，连接到 in 连接桩
    if (
      !sourceMagnet ||
      sourceMagnet.getAttribute('port-group') === 'in' ||
      sourceMagnet.getAttribute('port-group') === 'absolute_in'
    ) {
      return false
    }
    if (
      !targetMagnet ||
      targetMagnet.getAttribute('port-group') === 'out' ||
      targetMagnet.getAttribute('port-group') === 'absolute_out'
    ) {
      return false
    }

    // 不能重复连线
    const edges = this.getEdges()
    const portId = targetMagnet.getAttribute('port')
    if (edges.find((edge) => edge.getTargetPortId() === portId)) {
      return false
    }
    return true
  },
}

// -------------------------------------------------------------------------- //

// https://x6.antv.antgroup.com/api/registry/highlighter

export const highlightingOptions = {
  // 当连接桩可以被链接时，在连接桩外围渲染一个 1px 宽的淡橙色圆形框
  magnetAvailable: {
    name: 'stroke',
    args: {
      padding: 2,
      attrs: {
        strokeWidth: 1,
        stroke: 'rgba(252, 182, 96, 0.7)',
      },
      rx: 4,
      ry: 4,
    },
  },
  // 连接桩吸附连线时，在连接桩外围渲染一个 2px 宽 padding更大 的淡橙色圆形框
  magnetAdsorbed: {
    name: 'stroke',
    args: {
      padding: 6,
      attrs: {
        strokeWidth: 2,
        stroke: 'rgba(252, 182, 96, 0.7)',
      },
      rx: 4,
      ry: 4,
    },
  },
}

// -------------------------------------------------------------------------- //

// https://x6.antv.antgroup.com/tutorial/basic/interacting

export const interactingOptions = (graphStore: GraphStore) => {
  return {
    nodeMovable() {
      return graphStore.nodesMovable
    },
  }
}

// -------------------------------------------------------------------------- //
